home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 4 code / C++ Driver / iacDriver / TDriver.cp < prev    next >
Encoding:
Text File  |  1990-08-15  |  16.3 KB  |  430 lines  |  [TEXT/MPS ]

  1. // Copyright © 1990 Apple Computer, Inc. All rights reserved.
  2. #ifndef __IACHeaders__            // Every source file which uses the headers defined
  3. #include    "IACHeaders.h"            // In the main header file get the file included.  
  4. #endif
  5.  
  6. extern char *tseStrCpy(char *s,char *t);
  7.  
  8. /**********************************Comment*****************************************
  9. * TDriver::TDriver is the constructor.  It simply zeros the strings, and message
  10. * arrays.
  11.  **********************************End Comment************************************/
  12. TDriver::TDriver()
  13. {
  14. short        i, k;
  15. char        zeroChar = kZeroChar;
  16.  
  17. for (i = 0; i < kMaxApps; i++)
  18.     for (k = 0; k < 255; k++)
  19.         fAppNameArray[i][k] = kZeroChar;
  20. for (i = 0; i < kMaxMessages; i++)
  21.     fMessageArray[i] = nil;
  22. }
  23.  
  24. /**********************************Comment*****************************************
  25. * TDriver::~TDriver is the destructor.  It's just a place holder for the time being.
  26.  **********************************End Comment************************************/
  27. TDriver::~TDriver()
  28. {
  29. }
  30.  
  31.  
  32. /**********************************Comment*****************************************
  33. * TDriver::iacOpen would do any setup we needed to do when the driver was opened.
  34. * The constructor handles most of this for us.  You can put anything you like in
  35. * here, but I just return noErr.
  36.  **********************************End Comment************************************/
  37. OSErr
  38. TDriver::iacOpen(ParmBlkPtr oParmBlock)
  39. {
  40. #ifdef    DEBUG
  41.     DebugStr("\pIn Open now.");
  42. #endif
  43.  
  44. return (oParmBlock->ioParam.ioResult = noErr);
  45. }
  46.  
  47.  
  48. /**********************************Comment*****************************************
  49. * TDriver::iacPrime just returns an error explaining the two calls are not implemented
  50. * I could have used the flags in the DCE flags word to let the Device Manager handle
  51. * this notification to the caller.  But, again, I wanted to show how the routine
  52. * would be set up, and how to test the ioTrap word for the proper thing.
  53.  **********************************End Comment************************************/
  54. OSErr    
  55. TDriver::iacPrime(ParmBlkPtr pParmBlock)
  56. {
  57. #ifdef    DEBUG
  58.     DebugStr("\pIn Prime now.");
  59. #endif
  60. switch (pParmBlock->ioParam.ioTrap & 0x00FF)
  61.     {
  62.     case kRdCmd :
  63.          return (pParmBlock->ioParam.ioResult = kNoRead);
  64.     case kWrCmd :
  65.          return (pParmBlock->ioParam.ioResult = kNoWrite);
  66.     default :
  67.         break;
  68.     }; // switch statement.
  69. return(kNoErr);
  70. } // TDriver::iacPrime
  71.  
  72.  
  73. /**********************************Comment*****************************************
  74. * TDriver::iacControl does most of the work for us.  This is where we send and 
  75. * receive messages.  It's also where we register and unregister applications with
  76. * our driver.  We also have to handle KillIO calls because the chapter tells us to.
  77. * The tricky part is KillIO has to return via an RTS, so we'll signal the assembly
  78. * to RTS by putting a 1 in the return parameter.
  79. *
  80. * A special note about Virtual Memory here.  I chose to implement the send/receive
  81. * messages functionality here because I needed more information than just the 
  82. * actual message being passed -- I needed to know who it was from and who it was to.
  83. * This will cause a problem with VM if these Control calls are used at interrupt
  84. * time.  Virtual memory watches the _Read and _Write traps and makes sure the memory
  85. * addressed by ioBuffer stays in physical memory, but it neglects to do the same
  86. * for csParam.  Hence, the IACRecord structure (and pointers within that structure)
  87. * may or MAY NOT be in physical RAM at the time of the call.  If this happens at
  88. * interrupt time and a page fault occurs, we're completely hosed.
  89. * Now, to work around this in the future, I'd have to use the _Read and _Write traps
  90. * and format my ioBuffer to contain the information in IACRecord -- it'd have to 
  91. * pass ALL the information (with NO pointers to other information), so that's a bit
  92. * of a chore.  It's a particularly unpleasant aspect about VM, which could cause a
  93. * few device drivers to fail big-time.
  94. *
  95. * Note the particularly ugly type-cast of the csParam address.  We have to do this
  96. * so we can get a pointer (long) to the actual IACRecord structure.  You'll have to
  97. * do the same kind of thing when calling this routine.  Anyway, just to explain --
  98. * I take the address of the csParam structure, make it a pointer to a long, and then
  99. * dereference it.  Finally, I type-cast it to a pointer to an IACRecord structure.  
  100. * If you're in to experimenting, you might try doing different things to get at what
  101. * you THINK is the right address, and then dumpobj the result to see what the 
  102. * compiler did.  (that's what I had to do when I didn't understand why it was using
  103. * PEAs instead of MOVE.Ls.
  104.  **********************************End Comment************************************/
  105. OSErr    
  106. TDriver::iacControl(ParmBlkPtr cntlParmBlock)
  107. {
  108. #ifdef    DEBUG
  109.     DebugStr("\pIn Control now.");
  110. #endif
  111. switch (cntlParmBlock->cntrlParam.csCode)
  112.     {
  113.     case kKillIO:
  114.         return (cntlParmBlock->cntrlParam.ioResult = kAbnormErr);
  115.     case kGoodbye:
  116.         return(cntlParmBlock->cntrlParam.ioResult = noErr);
  117.     case kRegisterApp:
  118.         return (cntlParmBlock->cntrlParam.ioResult = this->RegisterApp( ((IACRecord *) *((long *) &(cntlParmBlock->cntrlParam.csParam)) )) );
  119.     case kSendMessage :
  120.         return (cntlParmBlock->cntrlParam.ioResult = this->SendMessage( ((IACRecord *) *((long *) &(cntlParmBlock->cntrlParam.csParam)) )) );
  121.     case kReceiveMessage :
  122.         return (cntlParmBlock->cntrlParam.ioResult = this->ReceiveMessage( ((IACRecord *) *((long *) &(cntlParmBlock->cntrlParam.csParam)) )) );
  123.     case kUnregisterApp :
  124.         return (cntlParmBlock->cntrlParam.ioResult = this->UnregisterApp( ((IACRecord *) *((long *) &(cntlParmBlock->cntrlParam.csParam)) )) );
  125.     default :
  126.         return (kBadCsCode);
  127.     }; // switch statement
  128. return(kNoErr);                 // The linker warns about "no return values" if I don't put this in.
  129. } // TDriver::iacControl
  130.  
  131.  
  132.  
  133. /**********************************Comment*****************************************
  134. * TDriver::iacStatus returns a couple of status-like pieces of information.  It calls
  135. * the AnyMessagesForMe routine to see if there are any messages addressed to the 
  136. * calling application.  It also calls WhosThere so a calling application can determine
  137. * which other applications have registered with the driver.  
  138. *
  139. * See the note above regarding the ugly type-cast.
  140. * See the note above regarding VM.
  141.  **********************************End Comment************************************/
  142. OSErr    
  143. TDriver::iacStatus(ParmBlkPtr sParmBlock)
  144. {
  145. #ifdef    DEBUG
  146.     DebugStr("\pIn Status now.");
  147. #endif
  148. switch (sParmBlock->cntrlParam.csCode)
  149.     {
  150.     case kAnyMsgForMe :
  151.         this->AnyMessagesForMe( ((IACRecord *) *((long *) &(sParmBlock->cntrlParam.csParam)) ));
  152.         return (sParmBlock->cntrlParam.ioResult = kNoErr);
  153.     case kWhosThere :
  154.         this->WhosThere( ((IACRecord *) *((long *) &(sParmBlock->cntrlParam.csParam)) )) ;
  155.         return (sParmBlock->cntrlParam.ioResult = kNoErr);
  156.     default :
  157.         return (kBadCsCode);
  158.     }; // switch statement
  159. return(kNoErr);                 // The linker warns about "no return values" if I don't put this in.
  160. } // TDriver::iacStatus
  161.  
  162.  
  163. /**********************************Comment*****************************************
  164. * TDriver::iacClose dispose of all the messages allocated, and unregister any
  165. * application names.
  166.  **********************************End Comment************************************/
  167. OSErr    
  168. TDriver::iacClose(ParmBlkPtr cParmBlock)
  169. {
  170. short        i;
  171. char        zeroChar = kZeroChar;
  172. TMessPtr    aMsgPtr;
  173.  
  174. #ifdef DEBUG
  175.     DebugStr("\pIn Close now.");
  176. #endif
  177.  
  178. for(i = 0; i < kMaxApps; i++)
  179.     {
  180.     if((this->GetAppName(i))[0] != kZeroChar)
  181.         this->SetAppName(i,&zeroChar);
  182.     }
  183. for(i = 0; i < kMaxMessages; i++)
  184.     {
  185.     if((aMsgPtr = this->GetMessage(i)))
  186.         {
  187.         DisposPtr((Ptr) aMsgPtr);
  188.         this->SetMessage(i,nil);
  189.         }
  190.     }
  191. return (cParmBlock->ioParam.ioResult = noErr);
  192. }
  193.  
  194.  
  195. // Private routines
  196.  
  197. /**********************************Comment*****************************************
  198. * TDriver::SetAppName is a standard Set routine.  It's the only place you'll find the
  199. * data member modified.  Thus, in the future, if I want to do something with how
  200. * the appname is stored, all I have to do is modify this routine.
  201. * I wanted the appname to be stored in the driver's storage, so we use the string
  202. * copy routine.
  203.  **********************************End Comment************************************/
  204. void
  205. TDriver::SetAppName(short signature,char *anAppName)
  206. {
  207. tseStrCpy((char *) &(fAppNameArray[signature]),anAppName);
  208. } // TDriver::SetAppName
  209.  
  210.  
  211. /**********************************Comment*****************************************
  212. * TDriver::GetAppName is a standard Get routine.  It's the only place you'll find the
  213. * data member returned.  Thus, in the future, if I want to do something with how
  214. * the appname is returned, all I have to do is modify this routine.
  215.  **********************************End Comment************************************/
  216. char*
  217. TDriver::GetAppName(short signature)
  218. {
  219. return (char *)&(fAppNameArray[signature]);
  220. }
  221.  
  222. /**********************************Comment*****************************************
  223. * TDriver::SetMessage is a standard Set routine.  It's the only place you'll find the
  224. * data member modified.  Thus, in the future, if I want to do something with how
  225. * the TMessage pointer is stored, all I have to do is modify this routine.
  226.  **********************************End Comment************************************/
  227. void
  228. TDriver::SetMessage(short index, TMessPtr aMsgPtr)
  229. {
  230. fMessageArray[index] = aMsgPtr;
  231. } // TDriver::SetMessage
  232.  
  233.  
  234. /**********************************Comment*****************************************
  235. * TDriver::GetMessage is a standard Get routine.  It's the only place you'll find the
  236. * data member returned.  Thus, in the future, if I want to do something with how
  237. * the message is returned, all I have to do is modify this routine.  As it is now,
  238. * a pointer to a TMessage object is returned.
  239.  **********************************End Comment************************************/
  240. TMessPtr
  241. TDriver::GetMessage(short index)
  242. {
  243. return (fMessageArray[index]);
  244. } // TDriver::GetMessage
  245.  
  246.  
  247. /**********************************Comment*****************************************
  248. * TDriver::AnyMessagesForMe returns TRUE if there are any messages which are being
  249. * sent to the app whose signature is anIACPtr->mySignature.  The routine will loop
  250. * through all the messages using GetMessage, and it'll as the MESSAGE if the message
  251. * is bound for the app whose signature is mySignature.  It will return the index of
  252. * where the message is in actualCount.  So, the caller can test for actualCount > 0
  253. * to see if there were any messages.  Otherwise, if there are no messages, actualCount
  254. * is set to kNoMore.
  255.  **********************************End Comment************************************/
  256. Boolean
  257. TDriver::AnyMessagesForMe(IACRecord    *anIACPtr)
  258. {
  259. TMessPtr     aMsgPtr;
  260. short            i;
  261.  
  262. anIACPtr->partnerSig = 0;
  263. anIACPtr->actualCount = kNoMore;
  264.  
  265. for (i = 0; i < kMaxMessages; i++)
  266.     {
  267.     if((aMsgPtr = GetMessage(i)) != nil)
  268.         {
  269.         if(aMsgPtr->IsMessageForMe(anIACPtr->mySignature))
  270.             anIACPtr->actualCount = i;
  271.         } // if message is not nil
  272.     } // for loop
  273.             
  274. return (anIACPtr->actualCount != kNoMore);
  275. } //  TDriver::AnyMessagesForMe
  276.  
  277.  
  278. /**********************************Comment*****************************************
  279. * TDriver::WhosThere returns, in the appName parameter the name of the
  280. * application whose signature is indexForWhosThere.  For a calling application to
  281. * find all registered apps, they'd start with indexForWhosThere at zero and loop
  282. * through until it returned zero in actualCount.  If there's only one application
  283. * registered, it's the one who's doing the calling.
  284. * The procedure stops once it has found just two applications registered.  It 
  285. * increments the indexForWhosThere so the next time through, it'll return the next
  286. * application name in appName.  It returns the signature of the "partner" in
  287. * partnerSig so the calling application can send messages.
  288.  **********************************End Comment************************************/
  289. void
  290. TDriver::WhosThere(IACRecord    *anIACPtr)
  291. {
  292. short    foundOne = 0, foundTwo = 0;
  293.  
  294. anIACPtr->actualCount = nil;
  295. anIACPtr->partnerSig = nil;
  296.  
  297. while ((anIACPtr->indexForWhosThere < kMaxApps) && (!foundTwo))
  298.     {
  299.     if((this->GetAppName(anIACPtr->indexForWhosThere))[0] != kZeroChar)
  300.         {
  301.         if(foundOne)
  302.             {
  303.             foundTwo = anIACPtr->indexForWhosThere;
  304.             anIACPtr->actualCount = kMoreMessages;
  305.             }
  306.         else
  307.             {
  308.             foundOne = anIACPtr->indexForWhosThere;
  309.             tseStrCpy(anIACPtr->appName,this->GetAppName(anIACPtr->indexForWhosThere));
  310.             anIACPtr->partnerSig = foundOne;
  311.             }
  312.         }
  313.     anIACPtr->indexForWhosThere++;
  314.     } // while
  315. } //  TDriver::WhosThere
  316.  
  317.  
  318.  
  319. /**********************************Comment*****************************************
  320. * TDriver::UnregisterApp receives all the messages for the particular application
  321. * which is unregistering.  Those messages will just get thrown away.  So, all the
  322. * messages destined for it are disposed of, and then it sets the name to '\0' so 
  323. * others can play.
  324.  **********************************End Comment************************************/
  325. short
  326. TDriver::UnregisterApp(IACRecord *anIACPtr)
  327. {
  328. char        zeroChar = kZeroChar;
  329.  
  330. while (this->ReceiveMessage(anIACPtr) == kYesMessagesForMe)        // gotta delete those suckers.
  331.     ;
  332. this->SetAppName(anIACPtr->mySignature,&zeroChar);                    // zero the name so others can play.
  333. return (kNoErr);
  334. } //  TDriver::UnregisterApp
  335.  
  336.  
  337. /**********************************Comment*****************************************
  338. * TDriver::RegisterApp looks to see if there's an open "slot".  If so, it sets the
  339. * new AppName for that "slot" and returns the "slot" as the signature.  If it couldn't
  340. * find any open "slots" then it returns the kNoMore error.
  341.  **********************************End Comment************************************/
  342. short
  343. TDriver::RegisterApp(IACRecord *anIACPtr)
  344. {
  345. short        i = 0;
  346. short        canDo = kNoMore;
  347.  
  348. while ((i < kMaxApps) && (canDo == kNoMore))
  349.     {
  350.     if((this->GetAppName(i))[0] == kZeroChar)
  351.         {
  352.         canDo = kNoErr;
  353.         anIACPtr->mySignature = i;
  354.         this->SetAppName(i,anIACPtr->appName);
  355.         }
  356.     i++;
  357.     }
  358. return (canDo);
  359. } //  TDriver::RegisterApp
  360.  
  361.  
  362. /**********************************Comment*****************************************
  363. * TDriver::SendMessage has to instantiate a new message object.  It also has to
  364. * remember that message for later when someone tries to receive it.  To remember it,
  365. * the TDriver object places it in the message pointer array.  If it couldn't find
  366. * an open "slot" in the array, it returns the error kMsgMemErr, meaning it has no
  367. * memory to store the pointer to the message and hence the message didn't get sent.
  368. * Since the TDriver object is creating a new TMessage, it will destroy the TMessage
  369. * when the time comes.
  370.  **********************************End Comment************************************/
  371. short
  372. TDriver::SendMessage(IACRecord    *anIACPtr)
  373. {
  374. TMessPtr    aMsgPtr;
  375. short        canDo = kNoMore;
  376. short        i = 0;
  377.  
  378. aMsgPtr = new TMessage(anIACPtr->messageString, anIACPtr->mySignature, anIACPtr->partnerSig);
  379. if(aMsgPtr)
  380.     {
  381.     while ((i < kMaxMessages) && (canDo == kNoMore))
  382.         {
  383.         if(this->GetMessage(i) == nil)
  384.             {
  385.             this->SetMessage(i, aMsgPtr);
  386.             canDo = kNoErr;
  387.             }
  388.         i++;
  389.         }
  390.     if (canDo == kNoMore)
  391.         delete aMsgPtr;
  392.     } // if aMsgPtr
  393. else
  394.     canDo = kMsgMemErr;
  395. return (canDo);        
  396. } //  TDriver::SendMessage
  397.  
  398.  
  399. /**********************************Comment*****************************************
  400. * TDriver::ReceiveMessage finds any messages for the application whose signature is
  401. * mySignature.  It first checks to see if there are any messages.  If so, it gets
  402. * the message, and asks the TMessage object to return the message string.  Then, it
  403. * copies the message string to the calling applications message buffer, puts the 
  404. * sender's signature in "partnerSig", and the sender's application name in appName.
  405. * It then sets the "slot" in the message array to nil, and disposes of the TMessage
  406. * object.  If there were messages, it returns the kYesMessagesForMe value, otherwise
  407. * it returns kNoMore.
  408.  **********************************End Comment************************************/
  409. short
  410. TDriver::ReceiveMessage(IACRecord    *anIACPtr)
  411. {
  412. TMessPtr        aMsgPtr;
  413. short            sender;
  414. char            *bufP = nil;
  415.  
  416. if(this->AnyMessagesForMe(anIACPtr))
  417.     {
  418.     aMsgPtr = this->GetMessage(anIACPtr->actualCount);
  419.     (void) aMsgPtr->IsMessageForMe(anIACPtr->mySignature,&sender,bufP);    
  420.     anIACPtr->partnerSig = sender;
  421.     tseStrCpy(anIACPtr->messageString,bufP);
  422.     tseStrCpy(anIACPtr->appName, this->GetAppName(anIACPtr->partnerSig));
  423.     this->SetMessage(anIACPtr->actualCount,nil);
  424.     delete aMsgPtr;
  425.     return (kYesMessagesForMe);
  426.     }
  427. else
  428.     return(kNoMore);
  429. } //  TDriver::ReceiveMessage
  430.